#pragma once
#include "../common/net.hpp"

namespace qiangsir
{
    namespace server
    {
        // 参数类型
        enum class param_type
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT,
        };
        class ServiceDescribe
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ServiceParamsDescribe = std::pair<std::string, param_type>;//参数<-->类型
            using ServiceCallBack = std::function<void(const Json::Value &, Json::Value &)>;
            ServiceDescribe(std::string &&method, ServiceCallBack &&callback,
                            std::vector<ServiceParamsDescribe> &&param_decs, param_type re_type)
                : _method(method), _callback(callback), _param_decs(param_decs), _re_type(re_type)
            {
            }
            // 参数类型检查
            bool paramsCheck(const Json::Value &params)
            {
                for (auto &des : _param_decs)
                {
                    if (params.isMember(des.first) == false)
                    {
                        ELOG("参数类型不存在");
                        return false;
                    }
                    if (check(des.second, params[des.first]) == false)
                    {
                        ELOG("参数类型校验失败");
                        return false;
                    }
                }
                return true;
            }
            // 业务函数调用
            bool call(const Json::Value &params, Json::Value &res)
            {
                _callback(params, res);
                if (checkRetype(res) == false)
                {
                    ELOG("回调函数中响应信息校验失败");
                    return false;
                }
                return true;
            }
            std::string method()
            {
                return _method;
            }

        private:
            bool checkRetype(const Json::Value &res)
            {
                return check(_re_type, res);
            }
            bool check(param_type type, const Json::Value &param)
            {
                switch (type)
                {
                case param_type::BOOL:
                    return param.isBool();
                case param_type::INTEGRAL:
                    return param.isIntegral();
                case param_type::STRING:
                    return param.isString();
                case param_type::NUMERIC:
                    return param.isNumeric();
                case param_type::ARRAY:
                    return param.isArray();
                case param_type::OBJECT:
                    return param.isObject();
                }
                return false;
            }

        private:
            std::string _method;                            // 业务名称
            ServiceCallBack _callback;                      // 业务回调
            std::vector<ServiceParamsDescribe> _param_decs; // 参数类型
            param_type _re_type;                            // 返回值参数
        };

        class ServiceDescribeFactor
        {
        public:
            void setMethodName(const std::string &name)
            {
                _method = name;
            }
            void setReturnType(param_type rtype)
            {
                _re_type = rtype;
            }
            void setParamsDesc(const std::string &pname, param_type vtype)
            {
                _param_decs.push_back(ServiceDescribe::ServiceParamsDescribe(pname, vtype));
            }
            void setCallback(const ServiceDescribe::ServiceCallBack &cb)
            {
                _callback = cb;
            }
            ServiceDescribe::ptr build()
            {
                return std::make_shared<ServiceDescribe>(move(_method), move(_callback),
                                                         move(_param_decs), _re_type);
            }

        private:
            std::string _method;                                             // 业务名称
            ServiceDescribe::ServiceCallBack _callback;                      // 业务回调
            std::vector<ServiceDescribe::ServiceParamsDescribe> _param_decs; // 参数类型
            param_type _re_type;
        };

        class ServiceManage
        {
        public:
            using ptr = std::shared_ptr<ServiceManage>;
            void insert(const ServiceDescribe::ptr &des)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _service_descs.insert(std::make_pair(des->method(), des));
            }
            ServiceDescribe::ptr slect(const std::string method)
            {
                std::unique_lock<std::mutex> lock(_mutex);

                auto it = _service_descs.find(method);
                if (it != _service_descs.end())
                {
                    return it->second;
                }
                return ServiceDescribe::ptr();
            }
            void remove(const std::string method)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _service_descs.erase(method);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServiceDescribe::ptr> _service_descs;
        };

        class RpcRouter
        {

        public:
            RpcRouter() : _services(std::make_shared<ServiceManage>()) {}
            using ptr = std::shared_ptr<RpcRouter>;
            //暴露给dispatcher
            void onRpcRequest(const BaseConnection::ptr &conn, RpcRequest::ptr &request)
            {
                // 1.检验方法是否存在
                auto service = _services->slect(request->method());
                if (service.get() == nullptr)
                {
                    ELOG("%s未找到该服务", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                }
                // 2.检验参数是否合法
                if (service->paramsCheck(request->params()) == false)
                {
                    ELOG("%s服务参数检验失败", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                }
                // 3.调用业务回调函数
                Json::Value res;
                bool ret = service->call(request->params(), res);
                // 4.构建应答
                if (ret == false)
                {
                    ELOG("%s服务返回参数检验失败", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }
                return response(conn, request, res, RCode::RCODE_OK);
            }
            void registerService(const ServiceDescribe::ptr &service)
            {
                _services->insert(service);
            }

        private:
            void response(const BaseConnection::ptr &conn, RpcRequest::ptr &request,
                          const Json::Value &result, RCode rcode)
            {
                auto msg = BaseMessageFactory::create<RpcResponse>();
                msg->setType(MType::RSP_RPC);
                msg->setId(request->id());
                msg->setResult(result);
                msg->setRcode(rcode);
                conn->send(msg);
            }

        private:
            ServiceManage::ptr _services;
        };
    }
}
